// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "content/renderer/shared_memory_seqlock_reader.h"

namespace content {
namespace internal {

    SharedMemorySeqLockReaderBase::SharedMemorySeqLockReaderBase() { }

    SharedMemorySeqLockReaderBase::~SharedMemorySeqLockReaderBase() { }

    void*
    SharedMemorySeqLockReaderBase::InitializeSharedMemory(
        base::SharedMemoryHandle shared_memory_handle, size_t buffer_size)
    {
        renderer_shared_memory_handle_ = shared_memory_handle;
        if (!base::SharedMemory::IsHandleValid(renderer_shared_memory_handle_))
            return 0;
        renderer_shared_memory_.reset(new base::SharedMemory(
            renderer_shared_memory_handle_, true));

        return (renderer_shared_memory_->Map(buffer_size))
            ? renderer_shared_memory_->memory()
            : 0;
    }

    bool SharedMemorySeqLockReaderBase::FetchFromBuffer(
        device::OneWriterSeqLock* seqlock,
        void* final,
        void* temp,
        void* from,
        size_t size)
    {
        if (!base::SharedMemory::IsHandleValid(renderer_shared_memory_handle_))
            return false;

        // Only try to read this many times before failing to avoid waiting here
        // very long in case of contention with the writer.
        int contention_count = -1;
        base::subtle::Atomic32 version;
        do {
            version = seqlock->ReadBegin();
            memcpy(temp, from, size);
            ++contention_count;
            if (contention_count == kMaximumContentionCount)
                break;
        } while (seqlock->ReadRetry(version));

        if (contention_count >= kMaximumContentionCount) {
            // We failed to successfully read, presumably because the hardware
            // thread was taking unusually long. Don't copy the data to the output
            // buffer, and simply leave what was there before.
            return false;
        }

        // New data was read successfully, copy it into the output buffer.
        memcpy(final, temp, size);
        return true;
    }

} // namespace internal
} // namespace content
